package cn.tedu.tmall.admin.mall.config;

import cn.tedu.tmall.admin.mall.filter.JwtAuthorizationFilter;
import cn.tedu.tmall.common.enumerator.ServiceCode;
import cn.tedu.tmall.common.web.JsonResult;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.io.PrintWriter;


@Configuration
//@EnableWebSecurity(debug = true)
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtAuthorizationFilter jwtAuthorizationFilter;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 允许跨域访问
        http.cors();

        // 调整Session创建策略，改为：不使用Session
        // SessionCreationPolicy.NEVER：从不主动创建Session，但是，如果Session已存在，则会使用它
        // SessionCreationPolicy.STATELESS：保持为“无状态”，具体表现为从不使用Session
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        // 将自定义的JWT过滤器添加到Security框架中特定的过滤器之前
        http.addFilterBefore(jwtAuthorizationFilter, UsernamePasswordAuthenticationFilter.class);

        // 处理"在未通过认证的情况下,想需要通过认证的资源发起请求,导致403错误"的问题
        /*http.exceptionHandling().authenticationEntryPoint(new AuthenticationEntryPoint() { //匿名内部类
            @Override
            public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
                response.setContentType("application/json;charset=utf-8");
                String message = "操作失败,您当前未登录,或登录已过期";
                JsonResult jsonResult = JsonResult.fail(
                        ServiceCode.ERROR_UNAUTHORIZED,message);
                String jsonString = JSON.toJSONString(jsonResult);
                PrintWriter writer = response.getWriter();
                writer.println(jsonString);
            }
        });*/

        http.exceptionHandling().authenticationEntryPoint((request, response, e) -> {  //将上述改为lambda表达式
            response.setContentType("application/json;charset=utf-8");
            String message = "操作失败,您当前未登录,或登录已过期";
            JsonResult jsonResult = JsonResult.fail(
                    ServiceCode.ERROR_UNAUTHORIZED,message);
            String jsonString = JSON.toJSONString(jsonResult);  //增加了转JSON的框架(添加了相关依赖)
            PrintWriter writer = response.getWriter();
            writer.println(jsonString);
        });

        // 禁用“防止伪造的跨域攻击的防御机制”  注:禁POST不会禁用GET请求
        http.csrf().disable();

        // 白名单
        // 不在白名单中的请求, 必须通过Security框架的认证机制,否则会响应403
        // Security框架的认证机制就是：检查SecurityContext中是否存在有效的Authentication
        String[] urls = {
                "/doc.html",
                "/**/*.css",
                "/**/*.js",
                "/swagger-resources",
                "/v2/api-docs",
                "/favicon.ico",
                "/users/login"
        };

        // 请求授权
        http.authorizeRequests() // 开始配置请求授权
                .mvcMatchers(urls) // 匹配某些请求
                .permitAll() // 许可，即不需要通过认证即可访问
                .anyRequest() // 匹配任何请求，实际表现为“除了以上配置过的以外的其它请求”
                .authenticated() // 需要已经通过认证
        ;

        // 根据是否调用formLogin()方法,表示是否启用登录页于登出页
        // 如果尝试访问某个"需要启用通过认证"的资源,但当前却未通过认证
        // -- 如果启用了登录页,则会自动重定向到登录页
        // -- 如果为启用登录页,则响应403错误
        // http.formLogin();
    }
}
